home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / external / rpc / rpc_clnt.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-07-08  |  34.1 KB  |  1,187 lines

  1. /* idl_rpc_client.c - Client side routines for the IDL RPC feature */
  2.  
  3. /*
  4.   Copyright (c) 1988-1997, Research Systems Inc.  All rights reserved.
  5.   This software includes information which is proprietary to and a
  6.   trade secret of Research Systems, Inc.  It is not to be disclosed
  7.   to anyone outside of this organization. Reproduction by any means
  8.   whatsoever is  prohibited without express written permission.
  9.  */
  10.  
  11. static char rcsid[] = "$Id: rpc_clnt.c,v 1.5 1997/01/29 21:17:45 kirk Exp $";
  12.  
  13.  
  14. /*
  15.  *  Contents:
  16.  *  This file contains routines that are used on the client side
  17.  *  of the IDL RPC routines. This includes all API functions as 
  18.  *  well as API support routines.
  19.  */
  20.  
  21.  
  22. /*
  23.  * Header files
  24.  */
  25.  
  26. #include "idl_rpc.h"
  27. #include "rpc_xdr.h"
  28.  
  29. #include <sys/time.h>
  30. #include <sys/socket.h>
  31. #include <netdb.h>
  32.  
  33. /*
  34.  * Declare the global timeout variable and set a default value
  35.  */
  36. static struct timeval   s_rpcTimeOut  = { 60, 0 }; /* default of 60 secs */
  37.  
  38. /*
  39.  * local functions 
  40.  */
  41. void idl_rpc_delvar(IDL_VPTR pVar);         /* deletes dynamic memory */
  42. void idl_rpc_strup(char * dst, char * src); /* upcases an char string */
  43. int idl_rpc_valid_str(char *s);                /* syntax check a command line */
  44. /*
  45.  * Declare the rpc buffer size
  46.  */
  47. #define      RPC_BUF_SIZE      (8*1024)
  48.  
  49. /*********************************************************************
  50.  * IDL_RPCInit()
  51.  *
  52.  * Purpose:
  53.  *    This function is used to perform the connection to the rpc server
  54.  *    and other startup initialization of the rpc client. All idl rpc
  55.  *    clients should call this routine before executing any IDL rpc
  56.  *    operations.
  57.  *
  58.  * entry:
  59.  *    lServerId      - integer ID of the rpc server. 0 => use default
  60.  *    pszHostname    - the hostname of the server. NULL => localhost
  61.  *
  62.  * exit:
  63.  *    Function returns a CLIENT pointer that references the client/server
  64.  *    connection or returns NULL if there was an error.
  65.  */
  66. CLIENT *IDL_RPCInit( long lServerId, char* pszHostname)
  67. {
  68.    int                   iSock = RPC_ANYSOCK;
  69.    struct hostent       *pHostent;
  70.    struct sockaddr_in    ServerAddr;
  71.    CLIENT               *pClient;
  72. /*
  73.  * Check input parameters
  74.  */
  75.    if(lServerId == 0)
  76.       lServerId = IDL_RPC_DEFAULT_ID;
  77.    
  78.    if( (pszHostname == (char*)NULL) || (*pszHostname == '\0'))
  79.        pszHostname = "localhost";
  80. /*
  81.  * Get the host information
  82.  */
  83.    if( (pHostent = gethostbyname(pszHostname)) == (struct hostent*)NULL){
  84.        perror("gethostbyname");
  85.        return (CLIENT*)NULL;
  86.      }
  87. /*
  88.  * Copy the host address into the server address struct
  89.  */
  90.    bcopy(pHostent->h_addr, (caddr_t)&ServerAddr.sin_addr, pHostent->h_length);
  91.    ServerAddr.sin_family      = AF_INET; /* address type */
  92.    ServerAddr.sin_port        = 0;
  93. /*
  94.  * Connect to the client usign TCP/IP
  95.  */
  96.    if( (pClient = (CLIENT*)clnttcp_create(&ServerAddr, lServerId, 
  97.              IDL_RPC_DEFAULT_VERSION, &iSock,
  98.              RPC_BUF_SIZE, RPC_BUF_SIZE)) == (CLIENT*)NULL){
  99.        clnt_pcreateerror("clnttcp_create");
  100.    }
  101.    return pClient;        /* return the client struct */
  102. }
  103. /******************************************************************
  104.  * IDL_RPCCleanup()
  105.  *
  106.  * Purpose:
  107.  *    This routine should be called when the user no longer desires to 
  108.  *    use the rpc server. This routine will unregister the client and
  109.  *    if desired by the user, halt the rpc server.      
  110.  *
  111.  * entry:
  112.  *    pClient    - The CLIENT ^ that refs the server/client connection
  113.  *             that will be affected.
  114.  *    iKill      - If true the RPC server will be killed.
  115.  *
  116.  * exit:
  117.  *    RPC client unregistered and if iKill was set, the server is killed.
  118.  *
  119.  */
  120. int IDL_RPCCleanup( CLIENT *pClient, int iKill)
  121. {
  122.    enum clnt_stat    rpcResult=RPC_SUCCESS;
  123. /*
  124.  * Does the user want to kill the server?
  125.  */
  126.    if(iKill)
  127.       rpcResult = clnt_call(pClient, IDL_RPC_CLEANUP, /* kill server */
  128.                 (xdrproc_t)xdr_void, 0, (xdrproc_t)xdr_void, 0, 
  129.                 s_rpcTimeOut);
  130.    if(pClient != (CLIENT*)NULL)
  131.       clnt_destroy(pClient);
  132.  
  133.    return (rpcResult == RPC_SUCCESS ? 1 : 0); 
  134. }
  135. /******************************************************************
  136.  * IDL_RPCTimeout()
  137.  *
  138.  * Purpose:
  139.  *    This routine is used to set the value of the rpc timeout being
  140.  *    used in the rpc calls to the server. The timeout value units 
  141.  *    are seconds. Returns 0 on failure.
  142.  *
  143.  * entry:
  144.  *    lTimeOut     - New timeout value in seconds.
  145.  *
  146.  * exit:
  147.  *    Returns 1 on success, 0 on failure. 
  148.  *    
  149.  */
  150. int IDL_RPCTimeout(long lTimeOut)
  151. {
  152. /*
  153.  * make sure that the timeout value looks "sane".
  154.  */
  155.    if(lTimeOut <= 0)
  156.       return 0;
  157.    s_rpcTimeOut.tv_sec = lTimeOut;
  158.    return 1;
  159. }
  160. /***************************************************************************
  161.  * idl_rpc_valid_str()
  162.  *
  163.  * Purpose:
  164.  *    This function checks to make sure that a string contains
  165.  *    a valid IDL command. Commands the start with $ or contain
  166.  *    "$" that are used for line continuations can cause the IDL 
  167.  *     server to hang. This function is used to validate command
  168.  *    lines before they are sent to the server.
  169.  *
  170.  * entry:
  171.  *     s    - command string to check.
  172.  *
  173.  * exit:
  174.  *    0 - command string is ok
  175.  *     -1 - command string is invalid
  176.  */
  177. int idl_rpc_valid_str(char *s)
  178. {
  179.    if(s == (char*)NULL) 
  180.       return 0;            /* valid */
  181.   
  182.    if(*s == '$')
  183.       return -1;            /* invalid */
  184. /*
  185.  * Loop thru and check for a '$'
  186.  */
  187.    while(*++s){
  188.      if( *s == '$'){
  189.      /*
  190.       * if this is preceeded by a alpha or an '_' it should be a
  191.       * variable name, otherwise signal an error.
  192.       */
  193.        if( !isalpha(*(s-1)) &&  *(s-1) != '_' && *(s-1) != '$')
  194.           return -1;
  195.      }
  196.    }  
  197.    return 0;    /* command string is OK */
  198. }
  199. /**********************************************************************
  200.  * IDL_RPCExecuteStr()
  201.  *
  202.  * Purpose:
  203.  *     This routine is used to send an IDL command string to the rpc
  204.  *     server. This string should be in the form of a single IDL command line.
  205.  *     The return value of this function is the value of !ERROR after 
  206.  *     the completion of the command.
  207.  *
  208.  * entry:
  209.  *     pClient        - The CLIENT ^ that refs the client/server connection.
  210.  *    pszCommand    - The command line to send to the server
  211.  *
  212.  * exit:
  213.  *    Return Value:
  214.  *        0     - Command executed ok.
  215.  *        -1    - Invalid command line.
  216.  *        other    - Value of !ERROR in the IDL server.
  217.  *
  218.  */
  219. int IDL_RPCExecuteStr( CLIENT *pClient, char * pszCommand)
  220.   enum clnt_stat     rpcResult;
  221.   int                iCmdResult;
  222. /* 
  223.  * check for a null command...why send it.
  224.  */
  225.    if(pszCommand == (char*)NULL)
  226.       return 1;            /* null commands are ok */
  227. /* 
  228.  * A command spawn using $ can cause problems and should not be sent
  229.  * to the server. Lets check for this.
  230.  */
  231.    if(idl_rpc_valid_str(pszCommand)){
  232.       fprintf(stderr, "IDL_RPCExecuteStr: %s\n",
  233.           "Shell command and line continue symbols not allowed");
  234.       return 0;
  235.     }
  236. /* 
  237.  * Send the command string to the server.
  238.  */
  239.    rpcResult = clnt_call(pClient, IDL_RPC_EXE_STR, 
  240.              (xdrproc_t)xdr_wrapstring, (char*)&pszCommand, 
  241.              (xdrproc_t)xdr_int, (char*)&iCmdResult,
  242.              s_rpcTimeOut);
  243.    if(rpcResult != RPC_SUCCESS){
  244.       clnt_perror( pClient, "IDL_RPCExecuteStr");
  245.       iCmdResult = 0;
  246.    }
  247.  
  248.    return iCmdResult;
  249. }
  250. /*****************************************************************
  251.  * IDL_RPCOutputCapture()
  252.  *
  253.  * Purpose:
  254.  *     This routine is used to enable and disable the capture of the 
  255.  *     output lines from IDL on the server side. If the input argument 
  256.  *     is greater than zero, the capture of output lines is enabled with
  257.  *     the size of the output queue (in lines) equal to the input parameter.
  258.  *     If the input parameter is <= zero, the caputure queue is emptied and
  259.  *     the capture of output lines is disabled.
  260.  *
  261.  * entry:
  262.  *     pClient        - The CLIENT ^ that refs the client/server connection.
  263.  *    n_lines        - The number of output lines to store. A value <=0 
  264.  *              disables the storage of output lines.
  265.  * exit:
  266.  *    Return Values:
  267.  *        1 - All is ok
  268.  *        0 - an error occurred.
  269.  */
  270. int IDL_RPCOutputCapture( CLIENT *pClient, int n_lines)
  271. {
  272.    enum clnt_stat     rpcResult;
  273.    int                iResult;
  274. /*
  275.  * Send the number of lines to capture to the server.
  276.  */
  277.    rpcResult = clnt_call(pClient, IDL_RPC_OUT_CAPTURE, 
  278.              (xdrproc_t)xdr_int, (char*)&n_lines, 
  279.              (xdrproc_t)xdr_int, (char*)&iResult,
  280.              s_rpcTimeOut);
  281.  
  282.    if(rpcResult != RPC_SUCCESS){
  283.       clnt_perror(pClient, "IDL_RPCOutputCapture");
  284.       return 0;
  285.    }
  286.    return 1; /* thats it */
  287. }
  288. /*******************************************************************
  289.  * IDL_RPCSetMainVariable()
  290.  *
  291.  * Purpose:
  292.  *    This function is used to set the value of a variable that 
  293.  *    is at the main level of the IDL RPC server. If the variable
  294.  *    doesnt exist at the main level on the server side, the server
  295.  *    will create it.
  296.  *
  297.  * entry:
  298.  *     pClient        - The CLIENT ^ that refs the client/server connection.
  299.  *    Name        - The name of the variable to be set.
  300.  *    pVar        - An IDL_VPTR that contains the value that the variable
  301.  *              should be set to.
  302.  * exit:
  303.  *   Return Values:
  304.  *        0 - ok
  305.  *        1 - Error occurred
  306.  */
  307. int IDL_RPCSetMainVariable( CLIENT *pClient, char *Name, IDL_VPTR pVar)
  308. {
  309.    enum clnt_stat   rpcResult;
  310.    IDL_RPC_VARIABLE rpcVar;    /* struct that holds vptr and Name */
  311.    int              iResult=0;
  312.    char             szBuffer[124];
  313. /*
  314.  * Put the information in the rpc variable structure and send it
  315.  * to the server.
  316.  */
  317.    idl_rpc_strup(szBuffer, Name);    /* upcase name */
  318.    rpcVar.name = szBuffer;
  319.    rpcVar.pVariable = pVar;
  320. /*
  321.  * If the variable is a string that is dynamically allocated, make
  322.  * sure that the V_DYNAMIC flag is set. With out this flag set,
  323.  * there can be problems on the server side.
  324.  */
  325.    if(pVar->type == IDL_TYP_STRING){
  326.       if(pVar->value.str.stype){
  327.          pVar->flags |= IDL_V_DYNAMIC;
  328.       }
  329.    }
  330. /*
  331.  * Send this info to the server.
  332.  */
  333.    rpcResult = clnt_call(pClient, IDL_RPC_SET_MAIN_VAR,
  334.              (xdrproc_t)IDL_RPC_xdr_variable, (char*)&rpcVar,
  335.              (xdrproc_t)xdr_void, 0, s_rpcTimeOut);
  336.  
  337.    if(rpcResult != RPC_SUCCESS){
  338.       clnt_perror(pClient, "IDL_RPCSetMainVariable");
  339.       return 0;
  340.    }
  341.    return 1;
  342. }
  343. /*************************************************************
  344.  * IDL_RPCGetMainVariable()
  345.  *
  346.  * Purpose:
  347.  *     This function is used to get the value of a variable 
  348.  *    that is located at the main IDL level on the IDL RPC server.
  349.  *    The IDL_VPTR that is returned from this function is dynamically
  350.  *    allocated and should be deallocated using the IDL_RPCDeltmp() 
  351.  *    function when the user is finished with it.
  352.  * 
  353.  * entry: 
  354.  *     pClient        - The CLIENT ^ that refs the client/server connection.
  355.  *    Name        - The name of the desired variable.
  356.  *
  357.  * exit:
  358.  *     Return Value:
  359.  *        On success this function returns an IDL_VPTR that points
  360.  *        to an IDL_VARIABLE structure that contains the value of 
  361.  *        the requested variable. On failure this function returns
  362.  *        NULL.
  363.  */
  364. IDL_VPTR IDL_RPCGetMainVariable(CLIENT *pClient, char *Name)
  365. {
  366.    IDL_VPTR pVar;
  367.    IDL_RPC_VARIABLE rpcVar;
  368.    enum clnt_stat   rpcResult;
  369.    char             szBuffer[124];
  370.    char           *pChar;
  371.    idl_rpc_strup(szBuffer, Name);    /* make sure it is uppercase */
  372.    bzero((char*)&rpcVar, sizeof(IDL_RPC_VARIABLE)); /* clear out  */
  373.    pChar = (char*)szBuffer;
  374. /* 
  375.  * Request the variable from the server
  376.  */
  377.    rpcResult = clnt_call(pClient, IDL_RPC_GET_MAIN_VAR,
  378.              (xdrproc_t)xdr_wrapstring, (char*)&pChar,
  379.              (xdrproc_t)IDL_RPC_xdr_variable, (char*)&rpcVar,
  380.              s_rpcTimeOut);
  381.    if(rpcResult != RPC_SUCCESS){
  382.       clnt_perror(pClient, "IDL_RPCGetMainVariable");
  383.       return (IDL_VPTR)NULL;
  384.    }
  385.    return rpcVar.pVariable;    /* return the value */
  386. }
  387. /*******************************************************************
  388.  * IDL_RPCSetVariable()
  389.  *
  390.  * Purpose:
  391.  *    This function is used to set the value of a variable that 
  392.  *    is in the current scope of the IDL RPC server. If the variable
  393.  *    doesnt exist at this level on the server side, the server
  394.  *    will create it.
  395.  *
  396.  * entry:
  397.  *     pClient        - The CLIENT ^ that refs the client/server connection.
  398.  *    Name        - The name of the variable to be set.
  399.  *    pVar        - An IDL_VPTR that contains the value that the variable
  400.  *              should be set to.
  401.  * exit:
  402.  *   Return Values:
  403.  *        0 - ok
  404.  *        1 - Error occurred
  405.  */
  406. int IDL_RPCSetVariable( CLIENT *pClient, char *Name, IDL_VPTR pVar)
  407. {
  408.    enum clnt_stat   rpcResult;
  409.    IDL_RPC_VARIABLE rpcVar;
  410.    int              iResult=0;
  411.    char             szBuffer[124];
  412. /*
  413.  * Put the information in the rpc variable structure and send it
  414.  * to the server.
  415.  */
  416.    idl_rpc_strup(szBuffer, Name);
  417.    rpcVar.name = Name;
  418.    rpcVar.pVariable = pVar;
  419.  
  420. /*
  421.  * If the variable is a string that is dynamically allocated, make
  422.  * sure that the V_DYNAMIC flag is set. With out this flag set,
  423.  * there can be problems on the server side.
  424.  */
  425.    if(pVar->type == IDL_TYP_STRING){
  426.       if(pVar->value.str.stype){
  427.          pVar->flags |= IDL_V_DYNAMIC;
  428.       }
  429.    }
  430. /*
  431.  * Send this info to the server.
  432.  */
  433.    rpcResult = clnt_call(pClient, IDL_RPC_SET_VAR,
  434.              (xdrproc_t)IDL_RPC_xdr_variable, (char*)&rpcVar,
  435.              (xdrproc_t)xdr_void, 0, s_rpcTimeOut);
  436.  
  437.    if(rpcResult != RPC_SUCCESS){
  438.       clnt_perror(pClient, "IDL_RPCSetVariable");
  439.       iResult=0;
  440.    }
  441.    return 1;
  442. }
  443. /*************************************************************
  444.  * IDL_RPCGetVariable()
  445.  *
  446.  * Purpose:
  447.  *     This function is used to get the value of a variable 
  448.  *    that is located in the current IDL scope on the IDL RPC server.
  449.  *    The IDL_VPTR that is returned from this function is dynamically
  450.  *    allocated and should be deallocated using the IDL_RPCDeltmp() 
  451.  *    function when the user is finished with it.
  452.  * 
  453.  * entry: 
  454.  *     pClient        - The CLIENT ^ that refs the client/server connection.
  455.  *    Name        - The name of the desired variable.
  456.  *
  457.  * exit:
  458.  *     Return Value:
  459.  *        On success this function returns an IDL_VPTR that points
  460.  *        to an IDL_VARIABLE structure that contains the value of 
  461.  *        the requested variable. On failure this function returns
  462.  *        NULL.
  463.  */
  464. IDL_VPTR IDL_RPCGetVariable(CLIENT *pClient, char *Name)
  465. {
  466.    IDL_VPTR pVar;
  467.    IDL_RPC_VARIABLE rpcVar;
  468.    enum clnt_stat   rpcResult;
  469.    char             szBuffer[124];
  470.    char            *pChar;
  471.    idl_rpc_strup(szBuffer, Name);    /* make sure it is uppercase */
  472.    pChar = (char*)szBuffer;
  473.    bzero((char*)&rpcVar, sizeof(IDL_RPC_VARIABLE)); /* clear out  */
  474.    rpcResult = clnt_call(pClient, IDL_RPC_GET_VAR,
  475.              (xdrproc_t)xdr_wrapstring, (char*)&pChar,
  476.              (xdrproc_t)IDL_RPC_xdr_variable, (char*)&rpcVar,
  477.              s_rpcTimeOut);
  478.    if(rpcResult != RPC_SUCCESS){
  479.       clnt_perror(pClient, "IDL_RPCGetVariable");
  480.       return (IDL_VPTR)NULL;
  481.    }
  482.    return rpcVar.pVariable;
  483. }   
  484. /*************************************************************
  485.  * IDL_RPCOuputGetStr()
  486.  *
  487.  * Purpose:
  488.  *     This function is used to get a line from the output queue that
  489.  *     is being kept on the RPC server. The routine IDL_RPCOutputCapture()
  490.  *     MUST have been called with a positive arguement before this routine.
  491.  *
  492.  * entry:
  493.  *    pClient        - The CLIENT ^ that refs the client/server connection.
  494.  *    pLine        - A ^ to a valid structure of type pLine. This 
  495.  *              structure will be filled with the next line
  496.  *              and information about this line.
  497.  *    first        - If not 0, the value should be popped from the 
  498.  *              output queue, not dequeued.
  499.  */
  500. int IDL_RPCOutputGetStr(CLIENT *pClient, IDL_RPC_LINE_S *pLine, int first)
  501. {
  502.    enum clnt_stat     rpcResult;
  503. /*
  504.  * Get the line from the server
  505.  */
  506.    rpcResult = clnt_call(pClient, IDL_RPC_OUT_STR, 
  507.              (xdrproc_t)xdr_int, (char*)&first, 
  508.              (xdrproc_t)IDL_RPC_xdr_line_s, (char*)pLine,
  509.              s_rpcTimeOut);
  510.    if(rpcResult != RPC_SUCCESS){
  511.       clnt_perror(pClient, "IDL_RPCOutputGetStr");
  512.       return 0;
  513.    }
  514. /*
  515.  * A flag value of -1 indicates that there are no more values
  516.  * in the ouput queue
  517.  */
  518.    return (pLine->flags == -1 ? 0 : 1);
  519. }
  520. /*************************************************************
  521.  * IDL_RPCVarCopy()
  522.  * 
  523.  * Purpose:
  524.  *     Used to emulate IDL_VarCopy() on the client side. The value
  525.  *     of the source variable is copied to the destination variable.
  526.  *    If the source variable has the IDL_V_TMP flag set, any dynamic
  527.  *    part of the source variable is moved to the destination variable
  528.  *    and not copied.
  529.  *    
  530.  *    Any dynamic memory associated with the destination variable
  531.  *    is freed before the copy is performed.
  532.  *
  533.  * entry:
  534.  *    src - ^ to variable to be copied.
  535.  *    dst - ^ to variable that will have info copied to it.
  536.  *
  537.  * exit:
  538.  *    src - not changed
  539.  *    dst - Any original dynamic data has been deallocated and it now
  540.  *          contains the value that was in src.
  541.  *
  542.  */
  543. void IDL_RPCVarCopy(IDL_VPTR src, IDL_VPTR dst)
  544. {
  545.    int flags;
  546.  
  547.    flags = dst->flags;        /* save the destination flags */
  548. /*
  549.  * Free up any dynamic memory used by the dst variable 
  550.  */
  551.    idl_rpc_delvar(dst);  
  552.    dst->flags = flags & ~(IDL_V_ARR & IDL_V_DYNAMIC); /* save some flags */
  553.    dst->type = src->type;    /* get the type of the copied var */
  554. /*
  555.  * Is the variable an array?
  556.  */
  557.    if( src->flags & IDL_V_ARR){
  558.    /*
  559.     * Is the source variable a *temporary* variable (or at least
  560.     * marked as such)? If so, just copy the arr pointer to the 
  561.     * src variable.
  562.     */
  563.       if(src->flags & IDL_V_TEMP){
  564.      dst->value.arr = src->value.arr;
  565.      src->flags &=  ~(IDL_V_NOT_SCALAR); /* take out array bit */
  566.      idl_rpc_delvar(src);    /* free any other memory being used */
  567.       }else{            /* need to copy over the data! */
  568.          dst->value.arr = (IDL_ARRAY*)malloc((unsigned)sizeof(IDL_ARRAY));
  569.      if(!dst->value.arr){
  570.         perror("malloc");
  571.         return;
  572.      }
  573.       /*
  574.        * Copy over the array info.
  575.        */
  576.      bcopy((char*)src->value.arr,(char*)dst->value.arr, sizeof(IDL_ARRAY));
  577.      dst->value.arr->data = (UCHAR*)malloc(src->value.arr->arr_len);
  578.      if(!dst->value.arr->data){
  579.         perror("malloc");
  580.         free((char*)dst->value.arr);
  581.         return;
  582.      }
  583.       /*
  584.        * Copy over the array info
  585.        */
  586.      bcopy((char*)src->value.arr->data, (char*)dst->value.arr->data, 
  587.            src->value.arr->arr_len);
  588.      dst->flags |= IDL_V_DYNAMIC;
  589.       }
  590.       dst->flags |= IDL_V_ARR;
  591.    }else {            /* a scalar */
  592.    /*
  593.     * just copy over the alltypes union
  594.     */
  595.       bcopy((char*)&dst->value, (char*)&src->value, sizeof(IDL_ALLTYPES));
  596.       dst->flags = dst->flags & ~(IDL_V_NOT_SCALAR);
  597.    }
  598. }
  599. /********************************************************************
  600.  * IDL_RPCDeltmp()
  601.  *
  602.  * Purpose:
  603.  *     This function emulates the IDL_Deltmp() function. This is used
  604.  *     to delete any dynamic memory that is allocated to create
  605.  *     a variable. This function calls idl_rpc_delvar() which keys off
  606.  *    the IDL_V_DYNAMIC flag or if a scalar is a string. 
  607.  *
  608.  *    If the IDL_V_TEMP bit is set, the IDL_VARIABLE will also be 
  609.  *    deallocated.
  610.  *
  611.  * entry:
  612.  *    vTmp  - A variable that will have its memory freed.
  613.  *
  614.  * exit:
  615.  *    vTmp - Any dynamic memory associated with vTmp is freed.
  616.  */
  617. void IDL_RPCDeltmp( IDL_VPTR vTmp)
  618. {
  619.    if(!vTmp)
  620.       return;   
  621. /*
  622.  * Free up any dynamic memory in the variable
  623.  */
  624.    idl_rpc_delvar(vTmp);
  625. /*
  626.  * If the IDL_V_TEMP bit is not set, return. 
  627.  */
  628.    if(!(vTmp->flags & IDL_V_TEMP))
  629.       return;
  630.    free((char*)vTmp);  /* free the IDL_VARIABLE */
  631. }
  632. /*********************************************************************
  633.  * IDL_RPCGettmp()
  634.  *
  635.  * Purpose:
  636.  *     Used to emulate the IDL function IDL_Gettmp(). Allocates
  637.  *     memory for an IDL_VARIABLE struct and returns a pointer 
  638.  *     to this value. The IDL_V_TEMP flag is set to indicate
  639.  *     that this value will need to be free'd later in the program.
  640.  *
  641.  * entry:
  642.  *    Nothing.
  643.  *
  644.  * exit:
  645.  *     Return Value:
  646.  *         Returns an IDL_VPTR that points to an IDL_VARIABLE 
  647.  *        struct with the IDL_V_TEMP bit set in the flags field.
  648.  *        On an error a NULL is returned.
  649.  */
  650. IDL_VPTR IDL_RPCGettmp(void)
  651. {
  652.    IDL_VPTR vTmp;
  653.  
  654.    vTmp = (IDL_VPTR)malloc((unsigned)sizeof(IDL_VARIABLE));
  655.    if(!vTmp){
  656.      perror("malloc");
  657.      return (IDL_VPTR)NULL;
  658.    }
  659.    bzero((char*)vTmp, sizeof(IDL_VARIABLE));
  660.    vTmp->flags = IDL_V_TEMP;  /* used to mark the IDL_VARIABLE as dynamic */
  661.    return vTmp;
  662. }
  663. /*********************************************************************
  664.  * IDL_RPCStoreScalar()
  665.  *
  666.  * Purpose:
  667.  *    This function is used to store a scalar value into an 
  668.  *    IDL_VPTR variable. This function emulates the Callable IDL
  669.  *    function IDL_StoreScalar.
  670.  *
  671.  * entry:
  672.  *     dest     - The ^ to the IDL_VARIABLE struct where the scalar
  673.  *          value is stored. Any dynamic memory that is contained
  674.  *          in dest will be deallocated before the store takes place.
  675.  *    type    - The type of the value to be stored.
  676.  *    value    - A ^ to an IDL_ALLTYPES union that contains the 
  677.  *          scalar value to store in the destination variable.
  678.  *
  679.  * exit:
  680.  *     The scalar value is stored in the destination variable.
  681.  */
  682. void IDL_RPCStoreScalar(IDL_VPTR dest, int type, 
  683.             IDL_ALLTYPES *value)
  684. {
  685.    int i;
  686.    IDL_STRING *pStr;
  687. /*
  688.  * Free up any dynamic memory being used by the variable
  689.  */
  690.    if(dest->flags & IDL_V_DYNAMIC)
  691.       idl_rpc_delvar(dest);
  692.    dest->flags=0;
  693. /* 
  694.  * Switch on the variable type and do the store.
  695.  */
  696.    switch(dest->type = type){
  697.    case IDL_TYP_BYTE: 
  698.       dest->value.c = value->c;
  699.       break;
  700.    case IDL_TYP_INT:
  701.       dest->value.i = value->i;
  702.       break;
  703.    case IDL_TYP_LONG:
  704.       dest->value.l = value->l;
  705.       break;
  706.    case IDL_TYP_FLOAT:
  707.       dest->value.f = value->f;
  708.       break;
  709.    case IDL_TYP_DOUBLE:
  710.       dest->value.d = value->d;
  711.       break;
  712.    case IDL_TYP_COMPLEX:
  713.       dest->value.cmp = value->cmp;
  714.       break;
  715.    case IDL_TYP_DCOMPLEX:
  716.       dest->value.dcmp = value->dcmp;
  717.       break;
  718.    case IDL_TYP_STRING:
  719.       dest->value.str = value->str;
  720.       IDL_RPCStrDup( &(dest->value.str), 1L);
  721.       dest->flags = IDL_V_DYNAMIC;    
  722.       break;
  723.    default:
  724.       fprintf(stderr,"IDL_RPCStoreScalar: Unknown Type");
  725.    }
  726.    return;  /* thats it, fairly simple */
  727. }
  728. /**************************************************************
  729.  * IDL_RPCMakeArray()
  730.  *
  731.  * Purpose:
  732.  *     This function is used to emulate the IDL function 
  733.  *     IDL_MakeTempArray() on the client side of the IDL RPC system.
  734.  *    This routine accepts parameters that describe the desired array,
  735.  *    and then creates a variable and allocates memory for the array.
  736.  *
  737.  *    The resulting array is marked such that all dynamic memory
  738.  *    will be deallocated by IDL_RPCDeltmp(), IDL_RPCVarCopy()..ect.
  739.  *
  740.  * entry:
  741.  *    type    - The IDL type code of the desired array.
  742.  *    n_dim    - The number of dimensions of the array.
  743.  *    dim    - An array that contains the size of each dimension.
  744.  *    init    - The type of initialization that is performed on the 
  745.  *          data block. If the value is set to IDL_BARR_INI_ZERO
  746.  *          the data block is cleared, otherwise no initialization
  747.  *          is done.
  748.  *    var    - A ^ to an IDL_VPTR. The address of the created variable
  749.  *          is placed in the location referenced by var.
  750.  *
  751.  * exit:
  752.  *    var     - referances the IDL_VPTR of the created variable.
  753.  *    Return Value:
  754.  *        On success the function returns the poniter to the array
  755.  *        data block. On failure, a NULL is returned.
  756.  *
  757.  */
  758. char * IDL_RPCMakeArray( int type, int n_dim, IDL_LONG dim[], 
  759.                 int init, IDL_VPTR *var)
  760. {
  761.    int      i;
  762.    char    *pData;
  763.    IDL_VPTR vTmp;
  764. /*
  765.  * Get a new IDL_VPTR
  766.  */
  767.    if( (vTmp = IDL_RPCGettmp()) == (IDL_VPTR)NULL)
  768.       return (char *)NULL;
  769. /*
  770.  * Alloc the array struct
  771.  */
  772.    vTmp->value.arr = (IDL_ARRAY*)calloc(1, sizeof(IDL_ARRAY));
  773.    if(!vTmp->value.arr){
  774.       IDL_RPCDeltmp(vTmp);
  775.       perror("calloc");
  776.       return((char*)NULL);
  777.    }
  778. /*
  779.  * Set up the vptr flags.
  780.  */
  781.    vTmp->flags |= IDL_V_ARR | IDL_V_DYNAMIC;
  782.    vTmp->type  = type;
  783.  
  784. /*
  785.  * Get the element size. Depends on the type. 
  786.  */
  787.    switch(type){
  788.    case IDL_TYP_BYTE:      
  789.      vTmp->value.arr->elt_len = sizeof(UCHAR);
  790.      break;
  791.    case IDL_TYP_INT:
  792.      vTmp->value.arr->elt_len = sizeof(short);
  793.      break;
  794.    case IDL_TYP_LONG:
  795.      vTmp->value.arr->elt_len = sizeof(IDL_LONG);
  796.      break;
  797.    case IDL_TYP_FLOAT:
  798.      vTmp->value.arr->elt_len = sizeof(float);
  799.      break;
  800.    case IDL_TYP_DOUBLE:
  801.      vTmp->value.arr->elt_len = sizeof(double);
  802.      break;
  803.    case IDL_TYP_COMPLEX:
  804.      vTmp->value.arr->elt_len = sizeof(IDL_COMPLEX);
  805.      break;
  806.    case IDL_TYP_DCOMPLEX:
  807.      vTmp->value.arr->elt_len = sizeof(IDL_DCOMPLEX);
  808.      break;
  809.    case IDL_TYP_STRING:
  810.      vTmp->value.arr->elt_len = sizeof(IDL_STRING);
  811.      break;
  812.    default:
  813.      break;
  814.    }
  815. /*
  816.  * Set the rest of the array fields, start with the number of 
  817.  * elements.
  818.  */
  819.    vTmp->value.arr->n_elts = 1;
  820.    for(i=0;i < n_dim; i++){
  821.      vTmp->value.arr->n_elts *= dim[i];
  822.      vTmp->value.arr->dim[i] = dim[i];
  823.    }
  824.    vTmp->value.arr->arr_len = vTmp->value.arr->elt_len *
  825.                   vTmp->value.arr->n_elts;
  826.    vTmp->value.arr->n_dim = n_dim;
  827.  /*
  828.  * Now allocate space for the data
  829.  */
  830.    pData = (char*)malloc(vTmp->value.arr->arr_len);
  831.    if(!pData){
  832.       perror("malloc");
  833.       IDL_RPCDeltmp(vTmp);
  834.       return((char*)NULL);
  835.    }
  836. /*
  837.  * Does the user want to initialize this to zero?
  838.  */
  839.    if(init == IDL_BARR_INI_ZERO)
  840.       bzero(pData, vTmp->value.arr->arr_len);
  841.             
  842.    vTmp->value.arr->data = (UCHAR*)pData;
  843.    *var = vTmp;            /* assign vptr to output */
  844.    
  845.    return pData;
  846. }
  847. /***************************************************************************
  848.  *IDL_RPCImportArray()
  849.  *
  850.  * Purpose:
  851.  *      This function is used to emulate the IDL function IDL_ImportArray()
  852.  *    on the client side of the IDL RPC system. This routine accepts 
  853.  *    a pointer to a data block that the user whishes to import into an
  854.  *    IDL variable as well as parameters that describe the attributes of 
  855.  *    the data. In addition to this information, the function accepts a
  856.  *    a pointer to a user supplied function that can be used to free 
  857.  *    the memory associated with the imported data.
  858.  *
  859.  *    The resulting array is marked such that all dynamic memory
  860.  *    will be deallocated by IDL_RPCDeltmp(), IDL_RPCVarCopy()..ect. as 
  861.  *     well as calling a user supplied memory deallocation call back function.
  862.  *
  863.  *     Note: This function does not support structure def. pointers as
  864.  *          does IDL_ImportArray(). Structures are not supported by the
  865.  *          RPC system. 
  866.  *  entry:
  867.  *    n_dim    - The number of dimesions in the array.
  868.  *    dim    - The number of elements of each dimension.
  869.  *    type    - The type of the array.
  870.  *    data    - Pointer to the array block that is being imported.
  871.  *    free_cb - Pointer to a function that should be called 
  872.  *              when freeing the data. If left null free() will be 
  873.  *          called.
  874.  *
  875.  *  exit:
  876.  *    Return Value:
  877.  *        On success, the function returns an IDL_VPTR that 
  878.  *        references the IDL_VARIABLE the contains the imported
  879.  *        array. On failure, NULL is returned.
  880.  */
  881. IDL_VPTR IDL_RPCImportArray(int n_dim, IDL_LONG dim[], int type, 
  882.                 UCHAR *data, IDL_ARRAY_FREE_CB free_cb)
  883. {
  884.    IDL_VPTR   pVptr;        /* vptr */
  885.    long       n_elements=1;
  886.    long       szElement;
  887.    int        i;
  888.  
  889. /*
  890.  * Are there any dimensions?
  891.  */
  892.    if(n_dim  <= 0){
  893.       fprintf(stderr, "IDL_RPCImportArray: Invalid Number of dimensions");
  894.       return (IDL_VPTR)NULL;
  895.    }
  896. /*
  897.  * What is the size of an element?
  898.  */
  899.    switch(type){
  900.    case IDL_TYP_INT:        szElement=sizeof(short); break;
  901.    case IDL_TYP_LONG:       szElement=sizeof(IDL_LONG); break;
  902.    case IDL_TYP_FLOAT:      szElement=sizeof(float); break;
  903.    case IDL_TYP_DOUBLE:     szElement=sizeof(double); break;
  904.    case IDL_TYP_COMPLEX:    szElement=sizeof(IDL_COMPLEX); break;
  905.    case IDL_TYP_DCOMPLEX:   szElement=sizeof(IDL_DCOMPLEX); break;
  906.    case IDL_TYP_STRING:     szElement=sizeof(IDL_STRING); break;
  907.    default:
  908.       fprintf(stderr, "IDL_RPCImportArray: Unknown Type\n");
  909.       return (IDL_VPTR)NULL;
  910.    }
  911. /*
  912.  * Get a temporary Variable
  913.  */ 
  914.    pVptr = IDL_RPCGettmp();
  915. /*
  916.  * Alloc an array block
  917.  */
  918.    pVptr->value.arr = (IDL_ARRAY*)calloc(1, sizeof(IDL_ARRAY));
  919.    if(!pVptr->value.arr){
  920.       IDL_RPCDeltmp(pVptr);
  921.       return (IDL_VPTR)NULL;
  922.    }
  923. /*
  924.  * Set-up the correct flags for the variable.
  925.  */
  926.    pVptr->flags |= IDL_V_ARR | IDL_V_DYNAMIC;
  927.    pVptr->type  = type;
  928.  
  929.    for(i=0; i<n_dim; i++){
  930.       pVptr->value.arr->dim[i] = dim[i];
  931.       n_elements *= dim[i];
  932.    }
  933.    pVptr->value.arr->elt_len = szElement;
  934.    pVptr->value.arr->n_dim = (UCHAR)n_dim;
  935.    pVptr->value.arr->arr_len = szElement*n_elements;
  936.    pVptr->value.arr->n_elts = n_elements;
  937.    pVptr->value.arr->free_cb = free_cb;
  938.    pVptr->value.arr->data = data;
  939. /*
  940.  * That's all
  941.  */
  942.    return pVptr;
  943. }
  944. /***************************************************************************
  945.  * idl_rpc_delvar
  946.  *
  947.  * Purpose:
  948.  *     This routine is used to free all of the dynamic memory associated
  949.  *     with a variable. This routine doesnt free the variable. This routine
  950.  *     should not be called by the user, but is used internally by the rpc
  951.  *     client side functions
  952.  * entry:
  953.  *    pVar    - A IDL_VPTR to the variable to have dynamic memory freed.
  954.  *
  955.  * exit:
  956.  *    pVar    - All dynamic memory associated with the variable( array 
  957.  *          and/or strings) is deallocated or a user call-back has been
  958.  *          called.
  959.  */
  960. void idl_rpc_delvar(IDL_VPTR pVar)
  961. {   
  962.    int i;
  963.    IDL_STRING *pStr;
  964.    int flags=0;
  965.  
  966.    flags = (IDL_V_TEMP & pVar->flags);
  967. /* 
  968.  * Check for an array.
  969.  */
  970.    if(pVar->flags & IDL_V_ARR){
  971.       if(pVar->flags & IDL_V_DYNAMIC){
  972.       /* 
  973.        * was a Free callback function declared?
  974.        */
  975.          if(pVar->value.arr->free_cb != (IDL_ARRAY_FREE_CB)NULL){
  976.         pVar->value.arr->free_cb((UCHAR*)pVar->value.arr->data);
  977.          }else{
  978.          /*
  979.           * Have a dynamic array that needs to be free'd. Is this a string 
  980.           * array?
  981.           */
  982.             if(pVar->type == IDL_TYP_STRING){
  983.            IDL_RPCStrDelete((IDL_STRING*)pVar->value.arr->data, 
  984.                 pVar->value.arr->n_elts);
  985.         }
  986.         free(pVar->value.arr->data);
  987.          }
  988.        }
  989.        free(pVar->value.arr); /* the array block is always dynamic */
  990.     }else if(pVar->type == IDL_TYP_STRING){
  991.        if(pVar->value.str.stype)
  992.       free(pVar->value.str.s);
  993.     }
  994. /*
  995.  *  Now just clear out the variable.
  996.  */
  997.     bzero((char*)pVar, sizeof(IDL_VARIABLE));
  998.     pVar->flags = flags; /* save temp flag. it is used to indicate  */
  999.              /* that the variable struct is dynamic */
  1000. }
  1001. /****************
  1002.  * String Section.
  1003.  ***********************************************************************
  1004.  * idl_rpc_strup()
  1005.  *
  1006.  * Purpose:
  1007.  *     Used to upcase a string.
  1008.  *
  1009.  * entry:
  1010.  *    dst    - The destination of the string variable.
  1011.  *    src    - The source string
  1012.  *
  1013.  * exit: 
  1014.  *    dst contains a upcased version of src.
  1015.  *
  1016.  */
  1017. void idl_rpc_strup(char * dst, char * src)
  1018. {
  1019.   char c;
  1020.   do{
  1021.     c = *src++;
  1022.     if(islower(c)) 
  1023.        c = toupper(c);
  1024.   }while(*dst++ = c);
  1025. }
  1026. /****************************************************************************
  1027.  * IDL_RPCStrDup()
  1028.  *
  1029.  * Purpose:
  1030.  *    
  1031.  *     This function is used to emulate the Callable IDL function 
  1032.  *     IDL_RPCStrDup(). This function should only be used on the client
  1033.  *     side of the RPC routines.
  1034.  *
  1035.  * entry:
  1036.  *        str     - A ^ to an IDL_STRING struct array.
  1037.  *    n    - The number of elements in the str.
  1038.  *
  1039.  * exit:
  1040.  *    str contains copies of the string values that where contained
  1041.  *    in the IDL_STRING structures.
  1042.  *    If an error is detected, the string struct is cleared.
  1043.  */
  1044. void IDL_RPCStrDup(IDL_STRING *str, IDL_LONG n)
  1045. {
  1046.    for(;n--; str++){
  1047.      if(str->slen && str->stype){ 
  1048.         if((str->s = (char*)strdup(str->s))==(char*)NULL)
  1049.        bzero( (char*)str, sizeof(IDL_STRING));
  1050.        else 
  1051.         str->stype = 1;    /* flag for dynamic */
  1052.      }
  1053.    }
  1054. }
  1055. /***************************************************************************
  1056.  * IDL_RPCStrDelete()
  1057.  *
  1058.  * Purpose:
  1059.  *     This routine is used to free any dynamic memory contained in the 
  1060.  *     string descriptors.
  1061.  *
  1062.  * entry:
  1063.  *    str    - A ^ to an IDL_STRING struct array.
  1064.  *    n    - The number of elements in str.
  1065.  *
  1066.  * exit:
  1067.  *    All dynamic values in the strings are deallocated and the 
  1068.  *    IDL_STRING structs are set to reflect this.
  1069.  *
  1070.  */
  1071. void IDL_RPCStrDelete(IDL_STRING *str, IDL_LONG n)
  1072. {
  1073.    for(;n--; str++){
  1074.    /*
  1075.     * Free the string if it is dynamic and has a length
  1076.     */
  1077.       if(str->slen && str->stype){
  1078.      free(str->s);
  1079.      bzero((char*)str, sizeof(IDL_STRING));
  1080.       }
  1081.    }
  1082. }
  1083. /***************************************************************************
  1084.  * IDL_RPCStrStore()
  1085.  *
  1086.  * Purpose:
  1087.  *     This routine is used to store a C string into an IDL String. The
  1088.  *     C string is strdup'd.
  1089.  * 
  1090.  * entry:
  1091.  *    s    - The ^ to a IDL_STRING struct that will get copy of the 
  1092.  *          C string.
  1093.  *    fs    - The C string to copy.
  1094.  * exit:
  1095.  *    s contains a copy of the C string or has been cleared if fs = null.
  1096.  */
  1097. void IDL_RPCStrStore( IDL_STRING *s, char *fs)
  1098. {
  1099.   int   len;
  1100.  
  1101.   if((len=strlen(fs))){
  1102.      s->s = (char*)strdup(fs);
  1103.      s->slen = len;
  1104.      s->stype=1;
  1105.   } else 
  1106.      bzero((char*)s, sizeof(IDL_STRING));
  1107. }
  1108. /***************************************************************************
  1109.  * IDL_RPCStrEnsureLength()
  1110.  *
  1111.  * Purpose:
  1112.  *     Used to ensure that a string is of a certain length.
  1113.  *
  1114.  * entry:
  1115.  *    s    - A ^ to a IDL_STRING struct that will get the string.
  1116.  *    n    - The lenght to be allocated.
  1117.  *
  1118.  * exit:
  1119.  *    The string field of the IDL_STRING struct is set to the desired length.
  1120.  */
  1121. void IDL_RPCStrEnsureLength(IDL_STRING *s, int n)
  1122. {
  1123.   if(n){            /* make a non-null dynamic string */
  1124.     if( ((int)s->slen < n) || !(s->stype)){
  1125.        IDL_RPCStrDelete(s, 1L);
  1126.        s->s = (char*)malloc((unsigned)sizeof(char)*n+1);
  1127.        if(!s->s){
  1128.       bzero((char*)s, sizeof(IDL_STRING));
  1129.       return;
  1130.        }
  1131.        s->stype=1;
  1132.     }
  1133.     s->slen = n;
  1134.   }else {            /* Want a null string */
  1135.     if(s->slen){        
  1136.        IDL_RPCStrDelete(s, 1L);
  1137.        bzero((char*)s, sizeof(IDL_STRING));
  1138.     }
  1139.   }
  1140. }
  1141. /***************************************************************************
  1142.  */
  1143. void IDL_RPCVarGetData(IDL_VPTR v, IDL_LONG *n, char **pd,
  1144.             int ensure_simple)
  1145. /*
  1146.  * Given a pointer to a varible, return the number of elements
  1147.  * and a pointer to the data area. This routine takes care of the
  1148.  * distinction between arrays and scalars.
  1149.  *
  1150.  * entry:
  1151.  *    v - Variable for which data is desired.
  1152.  *    n - Address of variable to receive # of elements.
  1153.  *    pd - Address of variable to receive pointer to data.
  1154.  *    ensure_simple - If TRUE, this routine calls the ENSURE_SIMPLE
  1155.  *        macro on the argument v to screen out variables of the
  1156.  *        types it prevents. Otherwise, EXCLUDE_FILE is called,
  1157.  *        because file variables have no data area to return.
  1158.  *
  1159.  * exit:
  1160.  *    *n - Receives count of elements.
  1161.  *    *pd - Receives pointer to data.
  1162.  */
  1163. {
  1164.  
  1165.   if(!v->type)
  1166.     return;
  1167.   if (ensure_simple) {
  1168.     if((v->flags &(IDL_V_FILE|IDL_V_STRUCT))||
  1169.        (v->type & (IDL_TYP_OBJREF|IDL_TYP_PTR)))
  1170.         return;
  1171.   } else {
  1172.     if(v->flags & IDL_V_FILE)
  1173.        return;
  1174.   }
  1175.   if (v->flags & IDL_V_ARR) {    /* Array? */
  1176.     *n = v->value.arr->n_elts;   /* Return values */
  1177.     *pd = (char *) v->value.arr->data;
  1178.   } else {
  1179.     *n = 1;            /* Scalar, one element */
  1180.     *pd = (char *) &v->value;
  1181.   }
  1182. }
  1183.  
  1184.  
  1185.  
  1186.